package de.jmda.gen.java.impl;

import java.util.LinkedList;
import java.util.List;

import org.apache.commons.lang.StringUtils;

import de.jmda.gen.Generator;
import de.jmda.gen.GeneratorException;
import de.jmda.gen.impl.AbstractCompoundGenerator;
import de.jmda.gen.java.AnnotationStatementGenerator;
import de.jmda.gen.java.AnnotationStatementsGenerator;

/**
 * Maintains list of {@link AnnotationStatementGenerator}s.
 *
 * @author rwegner
 */
public class DefaultAnnotationStatementsGenerator
		extends AbstractCompoundGenerator
		implements AnnotationStatementsGenerator
{
	private List<AnnotationStatementGenerator> annotationStatementGenerators;

	public DefaultAnnotationStatementsGenerator()
  {
	  super();
	  setComponentSeparator(System.lineSeparator());
  }

	/**
	 * @return list of <code>Generator</code>s with the return values of the
	 *         following methods in the following order:
	 *         <ul>
	 *           <li>{@link #getAnnotationStatementGenerators()}</li>
	 *         </ul>
	 *
	 * @see de.jmda.gen.CompoundGenerator#getGeneratorComponents()
	 */
	@Override
  public List<Generator> getGeneratorComponents()
  {
		// copy specific generators to non-specific generators and make Java happy
		List<Generator> result = new LinkedList<Generator>();

		result.addAll(getAnnotationStatementGenerators());
		
		return result;
  }

	/**
	 * Annotations are optional.
	 *
	 * @return {@link #annotationStatementGenerators}, if <code>null</code> it
	 *         will be lazily initialised to an empty, non <code>null</code> list.
	 *
	 * @see de.jmda.gen.java.AnnotationStatementsGenerator#getAnnotationStatementGenerators()
	 */
	@Override
  public List<AnnotationStatementGenerator> getAnnotationStatementGenerators()
  {
		if (annotationStatementGenerators == null)
		{
			annotationStatementGenerators =
					new LinkedList<AnnotationStatementGenerator>();
		}
		
		return annotationStatementGenerators;
  }

	/**
	 * Convenience method to add an <code>AnnotationStatementGenerator</code> to
	 * {@link #getAnnotationStatementGenerators()}.
	 *
	 * @param annotationStatementGenerator
	 */
	public void add(AnnotationStatementGenerator annotationStatementGenerator)
	{
		getAnnotationStatementGenerators().add(annotationStatementGenerator);
	}

	@Override
  public StringBuffer generate() throws GeneratorException
  {
	  return validate(super.generate());
  }
	
	/**
	 * @param input
	 * @return input
	 * @throws GeneratorException if compound generators produce multiple
	 *         identical annotation statements
	 */
	protected StringBuffer validate(StringBuffer input) throws GeneratorException
	{
		for (AnnotationStatementGenerator generator :
		     getAnnotationStatementGenerators())
		{
			String annotationStatement = generator.generate().toString();
			
			if (StringUtils.countMatches(input.toString(), annotationStatement) > 1)
			{
				throw new GeneratorException(
						"multiple occurence of identical annotation statement " +
						"[" + annotationStatement + "]");
			}
		}
		
		return input;
	}
}